#ifndef COFFSCREENSURFACE_H
#define COFFSCREENSURFACE_H

#include <QObject>
#include <QtGui/QOffscreenSurface>
#include <QtGui/QOpenGLContext>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLPaintDevice>
#include <QCoreApplication>
#include <QtGui/QPaintDevice>
#include <QtGui/QImage>
#include <QtGui/QExposeEvent>
#include <memory>
#include <atomic>
#include <mutex>
#include <QDebug>
class COffscreenSurface : public QOffscreenSurface,public QOpenGLFunctions
{
    Q_OBJECT
public:
    explicit COffscreenSurface(QScreen *screen = nullptr) :
        _initializedGL(false),
        _context(0),
        _device(0),
        _fbo(0),
        _resolvingFbo(0),
        _size(QSize(1,1))
    {
        setFormat(QSurfaceFormat::defaultFormat());
        _initialized=false;
        create();
        initializeInternal();
    }
    void initializeInternal();
    QOpenGLContext*context()const{
        return _context.get();
    }
    QOpenGLFunctions*functions()const
    {
        return (QOpenGLFunctions*)this;
    }
    unsigned int framebufferObjectHandle()const
    {
        return (_fbo?_fbo->handle():0);
    }
    const QOpenGLFramebufferObject*getFbo()const
    {
        return _fbo.get();
    }
    QPaintDevice*getDevice()const
    {
        return _device.get();
    }
    void bindFramebufferObject();
    void makeCurrent()
    {
        makeCurrentInternal();
    }
    void makeCurrentInternal();
    void doneCurrent();
    QImage grabFramebuffer();
    QImage grabFramebufferInternal(QOpenGLFramebufferObject*fbo);
    void swapBuffers()
    {
        swapBuffersInternal();
        emit frameSwapped();
    }
    void swapBuffersInternal();
    void recreateFboAndDevice();
    void update(){
        QCoreApplication::postEvent(this,new QEvent(QEvent::UpdateRequest));
    }
    void render();
    void exposeEvent(QExposeEvent*e)
    {
        render();
    }
    virtual void resizeEvent(QResizeEvent*e)
    {
        resize(e->size());
        emit resized();
    }
    virtual void resize(const QSize&nsize);
    void resize(int w,int h){resize(QSize(w,h));}
    virtual bool event(QEvent*e);
    virtual void initializeGL(){}
    virtual void paintGL(){}
    virtual void resizeGL(int w,int h){}
    virtual ~COffscreenSurface();
    bool isValid()const{
        return (_initialized&&_context&&_fbo);
    }

signals:
    void frameSwapped();
    void resized();
public slots:
protected:

    bool _initializedGL;
    std::atomic_bool _initialized;
    std::mutex _mutex;

    std::shared_ptr<QOpenGLContext> _context;
    std::shared_ptr<QOpenGLPaintDevice> _device;
    std::shared_ptr<QOpenGLFramebufferObject> _fbo;
    std::shared_ptr<QOpenGLFramebufferObject> _resolvingFbo;
    std::shared_ptr<QOpenGLShaderProgram> _shader;
    QSize _size;
};

#endif // COFFSCREENSURFACE_H
